﻿using log4net;
using log4net.Config;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MinerManager
{
	static class Program
	{
		static string Log4netConfigPath = System.Windows.Forms.Application.StartupPath + @"\log4net.config";
		static string AppPath = System.Windows.Forms.Application.StartupPath;
		static string AutoUpdateUri
		{
			get
			{
				return Common.ConfigHelper.GetAppSetting("NodeServerList");
			}
		}

		/// <summary>
		/// 应用程序的主入口点。
		/// </summary>
		[STAThread]
		static void Main()
		{
			string outputLog = System.Configuration.ConfigurationManager.AppSettings["OutputLog"];
			if (!string.IsNullOrWhiteSpace(outputLog) && outputLog == "1")
			{
				//初始化log4net  //var logger = LogManager.GetLogger(typeof(Program));
				var logCfg = new FileInfo(Log4netConfigPath);
				XmlConfigurator.ConfigureAndWatch(logCfg);
				//logger.Debug("初始化log4net");
			}

			//处理未捕获的异常  
			Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
			//处理UI线程异常  
			Application.ThreadException += Application_ThreadException;
			//处理非UI线程异常  
			AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

			//只允许一个实例在运行
			Process process = RuningInstance();
			if (process == null)
			{
				Application.EnableVisualStyles();
				Application.SetCompatibleTextRenderingDefault(false);

				if (CheckUpdate())
				{
					Forms.FrmUpdate update = new Forms.FrmUpdate();
					if (update.ShowDialog() == DialogResult.OK)
					{
						//Directory.SetCurrentDirectory(Directory.GetParent(AppPath).FullName);
						var path = Directory.GetParent(AppPath).FullName;

						if (File.Exists(System.IO.Path.Combine(path, "Updater.exe")))
						{
							System.Diagnostics.Process updateProcess = new System.Diagnostics.Process();
							updateProcess.StartInfo.FileName = "Updater.exe";
							updateProcess.StartInfo.WorkingDirectory = path;
							updateProcess.StartInfo.CreateNoWindow = true;
							updateProcess.Start();

							Application.Exit();
						}
						else
						{
							Application.Run(new Main());
						}
					}
					else
					{
						Application.Run(new Main());
					}
				}
				else
				{
					Application.Run(new Main());
				}
			}
			else
			{
				//MessageBox.Show("应用程序已经在运行中!");
				HandleRunningInstance(process);
			}
		}

		#region 全局错误捕捉器

		//处理UI线程异常  
		static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
		{
			ILog logger = LogManager.GetLogger(typeof(Program));
			Exception error = e.Exception as Exception;

			//记录日志 
			logger.Error(error.Message);
			logger.Error(error.StackTrace);
		}

		//处理非UI线程异常  
		static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
		{
			ILog logger = LogManager.GetLogger(typeof(Program));
			Exception error = e.ExceptionObject as Exception;

			//记录日志 
			logger.Error(error.Message);
			logger.Error(error.StackTrace);
		}

		#endregion

		#region bool CheckUpdate() 检查是否需要更新。

		/// <summary>  
		/// 检查是否需要更新。
		/// </summary>      
		public static bool CheckUpdate()
		{
			try
			{
				//Version verson = Assembly.LoadFrom(Application.ExecutablePath).GetName().Version;

				byte[] filedata = File.ReadAllBytes(Application.ExecutablePath);
				Assembly assembly = Assembly.Load(filedata);
				Version verson = assembly.GetName().Version;

				var newVerson = verson.ToString();
				WebClient wc = new WebClient();
				Stream stream = wc.OpenRead(AutoUpdateUri);

				StreamReader reader = new StreamReader(stream);
				string json = reader.ReadToEnd();

				Models.HttpNodeServer info = TomNet.Utility.Data.JsonHelper.FromJson<Models.HttpNodeServer>(json);
				if (info != null)
					newVerson = info.Ver;

				Version ver = new Version(newVerson);
				int tm = verson.CompareTo(ver);
				if (tm >= 0)
					return false;
				else
					return true;
			}
			catch //(Exception ex)
			{
				return false;
			}
		}

		#endregion

		#region 单独实例运行

		/// <summary>
		/// 该函数设置由不同线程产生的窗口的显示状态
		/// </summary>
		/// <param name="hWnd">窗口句柄</param>
		/// <param name="cmdShow">指定窗口如何显示。查看允许值列表，请查阅ShowWlndow函数的说明部分</param>
		/// <returns>如果函数原来可见，返回值为非零；如果函数原来被隐藏，返回值为零</returns>
		[DllImport("User32.dll")]
		private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);

		/// <summary>
		///  该函数将创建指定窗口的线程设置到前台，并且激活该窗口。键盘输入转向该窗口，并为用户改各种可视的记号。
		///  系统给创建前台窗口的线程分配的权限稍高于其他线程。 
		/// </summary>
		/// <param name="hWnd">将被激活并被调入前台的窗口句柄</param>
		/// <returns>如果窗口设入了前台，返回值为非零；如果窗口未被设入前台，返回值为零</returns>
		[DllImport("User32.dll")]
		private static extern bool SetForegroundWindow(IntPtr hWnd);

		private const int SW_SHOWNOMAL = 1;
		private static void HandleRunningInstance(Process instance)
		{
			ShowWindowAsync(instance.MainWindowHandle, SW_SHOWNOMAL);//显示
			SetForegroundWindow(instance.MainWindowHandle);//当到最前端
		}

		private static Process RuningInstance()
		{
			Process currentProcess = Process.GetCurrentProcess();
			Process[] Processes = Process.GetProcessesByName(currentProcess.ProcessName);
			foreach (Process process in Processes)
			{
				if (process.Id != currentProcess.Id)
				{
					if (process.MainModule.FileName == currentProcess.MainModule.FileName)
					{
						return process;
					}
				}
			}
			return null;
		}

		#endregion
	}
}
